const fs = require('fs')
const qiniu = require("qiniu");
const {join} = require("path");
const {get} = require("axios");
const uuid = require("uuid");
const path = require("path");
const bucket = "zhuzhequan"; //要上传的空间名
const host = "www.forgetting.ren"; // 空间绑定的域名
const accessKey = "BuSkZuviqzcXPCxTci0DtZyYHNoF3ydfRfZHETIw"; //Access Key
const secretKey = "X5NDlJfSzJaURWihIdFI8YHgG5lAbN_bWE_qwChP"; //Secret Key
const archiver = require('archiver');
const {readFileSync} = require("fs");
const moment = require("moment");

async function findFileAndDownload(list, date_dir_path) {
    for (let i in list) {
        let item = list[i]
        let p = path.join(date_dir_path, item.name)
        if (item.is_folder == '1') {
            fs.mkdirSync(p)
            if (item.children && item.children.length > 0) {
                await findFileAndDownload(item.children, p)
            }
        } else {
            const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
            const config = new qiniu.conf.Config();
            const bucketManager = new qiniu.rs.BucketManager(mac, config);
            const deadline = parseInt(Date.now() / 1000) + 3600; // 1小时过期
            const url = bucketManager.privateDownloadUrl('http://' + host, item.path, deadline)
            const res = await get(url, {responseType: 'arraybuffer'})
            fs.writeFileSync(p, res.data)
        }
    }
}

async function batchDownload(list) {
    return new Promise(async (resolve, reject) => {
        try {
            let dir_name = moment(new Date()).format('YYYY-MM-DD_HH_mm_ss')
            const dir_path = path.join(__dirname, '../temporary_files')
            const date_dir_path = path.join(dir_path, dir_name)
            if (!fs.existsSync(dir_path)) {
                fs.mkdirSync(dir_path)
            }
            fs.mkdirSync(date_dir_path)
            await findFileAndDownload(list, date_dir_path)
            const output = fs.createWriteStream(date_dir_path + '.zip');
            const archive = archiver('zip', {zlib: {level: 9}});// 设置压缩等级
            archive.on("error", function (err) {
                throw err;
            });
            archive.pipe(output);
            archive.directory(date_dir_path, false);
            await archive.finalize();

            resolve({zip: date_dir_path + '.zip', dir: date_dir_path})
        } catch (e) {
            reject(e)
            throw e.message
        }
    })


}

function downloadQiNiuUrl(key) {
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    const config = new qiniu.conf.Config();
    const bucketManager = new qiniu.rs.BucketManager(mac, config);
    const deadline = parseInt(Date.now() / 1000) + 3600; // 1小时过期
    return bucketManager.privateDownloadUrl('http://' + host, key, deadline)
}

function moveFileOrFolder(task) {
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    let config = new qiniu.conf.Config();
    const bucketManager = new qiniu.rs.BucketManager(mac, config);
    const m = [bucket, task.srcBucket, bucket, task.targetBucket]
    return new Promise(async (resolve, reject) => {
        try {
            let {data, resp} = await bucketManager
                .move(m[0], m[1], m[2], m[3], {force: true})
            console.log({data, resp, m},)
            if (resp.statusCode === 200) {
                resolve()
            } else {
                reject(data)
            }
        } catch (e) {
            reject(e)
        }
    })
}

function batchMoveFileOrFolder(tasks) {
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    let config = new qiniu.conf.Config();
    const bucketManager = new qiniu.rs.BucketManager(mac, config);
    const moveOperations = tasks.map(el => qiniu.rs.moveOp(bucket, el.srcBucket, bucket, el.targetBucket))
    return new Promise((resolve, reject) => {
        bucketManager
            .batch(moveOperations).then(({data, resp}) => {
            if (resp.statusCode === 200) {
                resolve('操作成功')
            } else {
                console.log({data, resp})
                reject('操作失败')
            }
        })

    })
}

async function createFolder(args) {
    console.log(args)
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    const options = {
        scope: bucket
    };
    const putPolicy = new qiniu.rs.PutPolicy(options);
    const uploadToken = putPolicy.uploadToken(mac);
    let config = new qiniu.conf.Config();
    if (args.body) args = args.body
    config.zone = qiniu.zone.Zone_z2;
    return new Promise(async (resolve, reject) => {
        const formUploader = new qiniu.form_up.FormUploader(config);
        const putExtra = new qiniu.form_up.PutExtra();
        const filePath = args.file_path + '/'
        await formUploader.putFile(uploadToken, filePath, join(__dirname, '../file.txt'), putExtra, (respErr, respBody, respInfo) => {
            // console.log(respErr, respBody, respInfo)
            if (respErr) {
                reject("");
            }
            if (respInfo.statusCode == 200) {
                console.log('上传成功')
                resolve({url: host + respBody.key});
            } else {
                console.log(respInfo)
                reject("上传失败");
                console.log('上传失败')
            }
        });
    });
}

async function deleteFolder(folderName) {
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    const config = new qiniu.conf.Config();
    const bucketManager = new qiniu.rs.BucketManager(mac, config);
    try {
        // 列出文件夹中的所有文件
        const options = {
            limit: 1000, // 每次最多列出 1000 个文件
            prefix: folderName, // 文件夹的前缀
        };

        const result = await new Promise((resolve, reject) => {
            bucketManager.listPrefix(bucket, options, (err, resBody, resInfo) => {
                if (err) {
                    reject(err);
                } else {
                    if (resInfo.statusCode === 200) {
                        resolve(resBody.items);
                    } else {
                        reject(new Error(`Failed to list files: ${resInfo.statusCode}`));
                    }
                }
            });
        });

        // 提取所有文件的 key
        const fileKeys = result.map(item => item.key);

        // 删除文件
        if (fileKeys.length > 0) {
            const deletePromises = fileKeys.map(key => {
                return new Promise((resolve, reject) => {
                    bucketManager.delete(bucket, key, (err, resBody, resInfo) => {
                        if (err) {
                            reject(err);
                        } else {
                            resolve(resBody);
                        }
                    });
                });
            });

            // 执行所有删除操作
            await Promise.all(deletePromises);
            console.log('Folder deleted successfully');
        } else {
            console.log('No files to delete in this folder');
        }
    } catch (error) {
        console.error('Error deleting folder:', error);
    }
}

async function completelyDeleteFiles(fileList) {
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    const config = new qiniu.conf.Config();
    const bucketManager = new qiniu.rs.BucketManager(mac, config);
    return new Promise(async (resolve, reject) => {
        let res = []
        try {
            for (let item of fileList) {
                let data
                if (item.path[item.path.length - 1] === '/') {
                    data = await deleteFolder(item.path)
                } else {
                    data = await bucketManager.delete(bucket, item.path)
                }
                res.push(data)
            }
            resolve(res)
        } catch (e) {
            console.log(e)
            reject(e)
        }
    })
}

async function uploadByFile(file, args, isDelete = true) {
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    const options = {
        scope: bucket
    };
    if (args.body) args = args.body
    const putPolicy = new qiniu.rs.PutPolicy(options);
    const uploadToken = putPolicy.uploadToken(mac);
    let config = new qiniu.conf.Config();
    config.zone = qiniu.zone.Zone_z2;
    return new Promise(async (resolve, reject) => {
        const formUploader = new qiniu.form_up.FormUploader(config);
        const putExtra = new qiniu.form_up.PutExtra();
        const filePath = args.file_path
        await formUploader.putFile(uploadToken, filePath, file.filepath, putExtra, (respErr, respBody, respInfo) => {
            // console.log(respErr, respBody, respInfo)
            if (respErr) {
                reject("");
            }
            if (respInfo.statusCode == 200) {
                console.log('上传成功')
                resolve({url: host + respBody.key});
            } else {
                console.log(respInfo)
                reject("上传失败");
                console.log('上传失败')
            }
            if (isDelete) {
                fs.unlinkSync(file.filepath);
            }

        });
    });
}

async function uploadChunk(args) {
    return new Promise(async (resolve, reject) => {
        let {index, filepath, totalChunks, file_path} = args
        const chunkSize = 4 * 1024 * 1024; // 4MB
        const file = readFileSync(filepath)
        let chunks = null;
        for (let i = 0; i < totalChunks; i++) {
            if (i === index) {
                const start = i * chunkSize;
                const end = Math.min(start + chunkSize, file.length);
                chunks = file.slice(start, end); // 获取当前分片
            }
        }

        const startByte = (index - 1) * chunkSize;
        const endByte = Math.min(index * chunkSize, args.size);
        const fileStream = fs.createReadStream(filepath, {start: startByte, end: endByte});
        const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
        const options = {
            scope: bucket
        };
        const putPolicy = new qiniu.rs.PutPolicy(options);
        const uploadToken = putPolicy.uploadToken(mac);
        const config = new qiniu.conf.Config();
        const resumeUploader = new qiniu.resume_up.ResumeUploader(config);

        const putExtra = new qiniu.resume_up.PutExtra();
        putExtra.version = "v2";
        putExtra.partSize = chunkSize;
        await resumeUploader.putStream(uploadToken, file_path, fileStream, 4, putExtra, function (err, body, info) {
            console.log({err, body, info})
            if (info.statusCode == 200) {
                console.log('上传成功')
                resolve();
            } else {
                reject("上传失败");
                console.log('上传失败')
            }
        });
    })

}

module.exports = {
    batchDownload,
    downloadQiNiuUrl,
    moveFileOrFolder,
    batchMoveFileOrFolder,
    uploadChunk,
    createFolder,
    deleteFolder,
    completelyDeleteFiles,
    uploadByFile,
}
